package com.zeyu.framework.monitors.server.utils;

import com.google.common.collect.Lists;
import com.google.common.io.Resources;
import com.zeyu.framework.FrameworkApplication;
import com.zeyu.framework.utils.StringUtils;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.List;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;

/**
 * sigar tools
 * Created by zeyuphoenix on 16/8/27.
 */
public class SigarUtils {

    // ================================================================
    // Constants
    // ================================================================

    /**
     * logger
     */
    private static final Logger logger = LoggerFactory.getLogger(SigarUtils.class);

    // ================================================================
    // Fields
    // ================================================================

    // ================================================================
    // Constructors
    // ================================================================

    // ================================================================
    // Methods from/for super Interfaces or SuperClass
    // ================================================================

    // ================================================================
    // Public or Protected Methods
    // ================================================================

    /**
     * 加载dll、so、lib等库、初始化
     */
    public static void loadLibrary() {
        try {
            // 获取当前class路径,判断属于jar还是class方式启动
            String pwd = SigarUtils.class.getResource(SigarUtils.class.getSimpleName() + ".class").getPath();
            logger.debug("now class path is {}", pwd);
            String file;
            if (pwd.contains(".jar!") && !FrameworkApplication.TOMCAT_SERVER_STARTING) {
                // jar方式
                logger.info("load library with jar file");
                file = System.getProperty("java.io.tmpdir") + File.separator + "sigar";
                logger.debug("library path is {}", file);
                File tmpFile = new File(file);
                if (!tmpFile.exists()) {
                    boolean mkdirs = tmpFile.mkdirs();
                    if (mkdirs && tmpFile.exists()) {
                        // extracted lib file
                        extractedLib(tmpFile);
                    }
                }
            } else {
                // class方式
                logger.info("load library with class file");
                file = Resources.getResource("sigar").getFile();
                logger.debug("library path is {}", file);
            }

            String path = System.getProperty("java.library.path");
            if (OsCheck.getOperatingSystemType() == OsCheck.OSType.Windows) {
                path += ";" + new File(file).getCanonicalPath();
            } else {
                path += ":" + new File(file).getCanonicalPath();
            }
            logger.debug("now java classpath is {} ", path);
            System.setProperty("java.library.path", path);

        } catch (Exception e) {
            logger.error("load sigar library error: ", e);
        }
    }

    // ================================================================
    // Getter & Setter
    // ================================================================

    // ================================================================
    // Private Methods
    // ================================================================

    /**
     * 解压jar内library到指定目录
     * @param tmpFile 解压目录
     */
    private static void extractedLib(File tmpFile) throws UnsupportedEncodingException, URISyntaxException {
        // 获取jar的路径
        URL location = SigarUtils.class.getProtectionDomain().getCodeSource().getLocation();
        String jarPath = URLDecoder.decode(location.getPath(), "utf-8");
        logger.debug("jar file path is {}", jarPath);

        // windows系统可以mac系统下,前面多一个file: 后面多一个!/
        jarPath = StringUtils.replace(jarPath, "file:", "");
        // 每个版本都不一样,需要去不同系统验证
        jarPath = getJarPath(jarPath);

        JarFile jarFile = null;
        try {
            // find all library
            jarFile = new JarFile(new File(jarPath));
            Enumeration<JarEntry> entries = jarFile.entries();
            List<String> libs = Lists.newArrayList();
            while (entries.hasMoreElements()) {
                JarEntry entry = entries.nextElement();
                if (StringUtils.startsWith(entry.getName(), "sigar")) {
                    if (!entry.isDirectory()) {
                        libs.add(entry.getName());
                    }
                }
            }
            logger.debug("copy to classpath file is {}", libs);

            // copy library
            for (String lib : libs) {
                InputStream is = SigarUtils.class.getResourceAsStream("/" + lib);
                OutputStream os = new FileOutputStream(new File(tmpFile, getJarFileName(lib)));

                IOUtils.copy(is, os);

                is.close();
                os.close();
            }


        } catch (Exception e) {
            logger.error("open jar file error ", e);
        } finally {
            try {
                if (jarFile != null)
                    jarFile.close();
            } catch (IOException ignored) {
            }
        }
    }


    /**
     * 根据路径获取jar内文件名称
     */
    private static String getJarFileName(String path) {
        return path.substring(path.lastIndexOf("/"));
    }

    /**
     * 匹配不同规则去除jar的后缀
     */
    private static String getJarPath(String path) {
        int index = StringUtils.indexOf(path, ".jar!");
        if (index > -1) {
           return StringUtils.substring(path, 0, index + 4);
        }
        return path;
    }

    // ================================================================
    // Inner or Anonymous Class
    // ================================================================

    // ================================================================
    // Test Methods
    // ================================================================

}
